package org.ala.tiktools.tools;


import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author ala
 * @date 2025-03-17 09:44
 */
public class TimestampTools {

    /**
     *  毫秒数单位
     */
    public static final long DAY_MS = 1l * 24l * 3600l * 1000l,
                                HOUR_MS = 3600l * 1000l,
                                MINUTE_MS = 60l * 1000l;


    /**
     *  当前时刻
     */
    public static Timestamp now() {
        return new Timestamp(System.currentTimeMillis());
    }
    /**
     *  几天后的时刻（参数可以搜负数）
     */
    public static Timestamp afteNow(int day) {
        return new Timestamp(System.currentTimeMillis() + day * DAY_MS);
    }
    /**
     *  几天后的时刻（参数可以搜负数）
     */
    public static Timestamp afte(Timestamp time, int day) {
        return new Timestamp(time.getTime() + day * DAY_MS);
    }
    /**
     *  时间戳转换为当天的时间戳区间（左右闭区间）
     */
    public static List<long[]> cutByDay(long gte, long lte) {
        List<long[]> res = new ArrayList<>();
        long[] now = new long[]{gte, gte + (DAY_MS - gte % DAY_MS - 8 * HOUR_MS) - 1};
        res.add(now);
        while (now[1] < lte) {
            now = new long[]{now[1] + 1, now[1] + DAY_MS};
            res.add(now);
        }
        res.get(res.size() - 1)[1] = lte;
        return res;
    }


    /**
     *  当前的纳秒时间戳转为32位
     */
    public static int milliSeconds32() {
        return (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
    }
    /**
     * 	当前微秒
     * 	<p>	从jvm启动时开始算，不是1970年
     */
    public static long microSecond() {
    	return TimeUnit.MICROSECONDS.convert(System.nanoTime(), TimeUnit.NANOSECONDS);
    } 


    /**
     *  通过毫秒时间戳构建Timestamp
     */
    public static Timestamp instanceOf(long timestamp) {
        return new Timestamp(timestamp);
    }
    /**
     *  毫秒表示的天数
     */
    public static int day(long timestamp) {
        return (int)(timestamp / DAY_MS) + (timestamp % DAY_MS > 0 ? 1 : 0);
    }


    /**
     *  通过毫秒数格式化年月日
     */
    public static String formatYYYYMMDD(long timestamp) {
        int[] r = yyyyMMdd(timestamp);
        return formatYYYYMMDD(r);
    }
    /**
     *  通过日期拼年月日
     */
    public static String formatYYYYMMDD(int[] date) {
        StringBuilder sbuf = new StringBuilder();
        sbuf.append(date[0]);
        if (date[1] < 10) {sbuf.append("0").append(date[1]);}
        else {sbuf.append(date[1]);}
        if (date[2] < 10) {sbuf.append("0").append(date[2]);}
        else {sbuf.append(date[2]);}
        return sbuf.toString();
    }
    /**
     *  通过毫秒数计算年月日小时分秒
     */
    public static int[] yyyyMMdd(long timestamp) {
        Calendar c = new Calendar.Builder().setInstant(timestamp).build();
        return new int[] {c.get(Calendar.YEAR),
                c.get(Calendar.MONTH) + 1,
                c.get(Calendar.DAY_OF_MONTH)};
        //  总天数
//        int day = day(timestamp);
//
//        //  当前毫秒数相对于当天的毫秒数，计算24小时制的小时分秒（乘法比模运算更快）
//        long relativeTime = timestamp - day * DAY_MS;
//
//        //  根据总天数算出来是第几年
//        int year = bsDay(day, SumDaysByYear) - 1;
//        day -= SumDaysByYear[year] - 1;     //  （从1开始，所以减去的结果要加回来）
//        year += 1970;
//
//        //  根据剩余天数算出是第几月
//        int[] dayInMonth = isLeapYear(year) ? DayInMonthLeapYear : DayInMonth;
//        int month = bsDay(day, dayInMonth);
//
//        //  扣除月份的相对天数，就是第几月的第几天
//        day -= dayInMonth[month-1];
//        return new int[] {year, month, day};
    }


    /**
     *  通过毫秒数格式化年月日
     */
    public static String formatYYYYMMDDHHmmss(long timestamp) {
        int[] r = yyyyMMddHHmmssSSS(timestamp);
        StringBuilder sbuf = new StringBuilder();
        sbuf.append(r[0]);

        if (r[1] < 10) {sbuf.append("0").append(r[1]);}
        else {sbuf.append(r[1]);}

        if (r[2] < 10) {sbuf.append("0").append(r[2]);}
        else {sbuf.append(r[2]);}

        if (r[3] < 10) {sbuf.append("0").append(r[3]);}
        else {sbuf.append(r[3]);}

        if (r[4] < 10) {sbuf.append("0").append(r[4]);}
        else {sbuf.append(r[4]);}

        if (r[5] < 10) {sbuf.append("0").append(r[5]);}
        else {sbuf.append(r[5]);}
        return sbuf.toString();
    }
    /**
     *  通过毫秒数计算年月日小时分秒
     */
    public static int[] yyyyMMddHHmmssSSS(long timestamp) {
        Calendar c = new Calendar.Builder().setInstant(timestamp).build();
        return new int[] {c.get(Calendar.YEAR),
                c.get(Calendar.MONTH) + 1,
                c.get(Calendar.DAY_OF_MONTH),
                c.get(Calendar.HOUR_OF_DAY),
                c.get(Calendar.MINUTE),
                c.get(Calendar.SECOND),
                c.get(Calendar.MILLISECOND)
        };
    }



    /**
     *  从1970到2100年，每年的天数前缀和
     */
    static int[] SumDaysByYear;
    /**
     *  一年中每月的天数 和 润年中每月的天数 的前缀和
     */
    static int[] DayInMonth = null,
                    DayInMonthLeapYear = null;
    static {
        //  计算年份天数前缀和
        SumDaysByYear = new int[2100 - 1970 + 1 + 1];
        int p = 1;
        for (int i = 1970 ; i <= 2100 ; i++) {
            int d = 365;
            if (isLeapYear(i)) {
                d++;
            }
            SumDaysByYear[p] = SumDaysByYear[p-1] + d;
            p++;
        }
        //  计算每月天数前缀和
        DayInMonth = new int[13];
        DayInMonthLeapYear = new int[13];
        int[] ds = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                dsl ={31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        for (int i = 1 ; i <= 12 ; i++) {
            DayInMonth[i] = DayInMonth[i-1] + ds[i-1];
            DayInMonthLeapYear[i] = DayInMonthLeapYear[i-1] + dsl[i-1];
        }
    }
    /**
     *  是否是润年
     */
    public static boolean isLeapYear(int year) {
        return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
    }
    /**
     *  二分找 >= v 的第一个数
     */
    static int bsDay(int v, int[] nums) {
        int N = nums.length;
        if (v <= nums[1]) {return 1;}
        if (v > nums[N-1]) {return N;}
        for (int l = 0, r = N-1 ; l < r ;) {
            int m = l + ((r-l)>>1);
            if (nums[m] == v) {return m;}
            boolean b = v > nums[m];
            if (l == m) {
                return r;
            }
            if (b) {l = m;}
            else {r = m;}
        }
        return -1;
    }
}
